/*******************************************************************************
 * Copyright 2013 Mindaugas Idzelis
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package incontrol.server;

import static com.google.common.collect.Maps.newHashMap;
import incontrol.bf3.state.ServerState;
import incontrol.core.Config;
import incontrol.rcon.protocol.RCONClient;

import java.util.Map;

import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.bayeux.server.LocalSession;
import org.cometd.client.transport.ClientTransport;
import org.cometd.common.JSONContext;
import org.cometd.server.BayeuxServerImpl;
import org.cometd.server.CometdServlet;
import org.cometd.server.JacksonJSONContextServer;
import org.cometd.websocket.server.WebSocketTransport;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import com.google.common.net.HostAndPort;

public class IncontrolServer {

	private LocalSession serverSession;
	private BayeuxServerImpl bayeuxServer;

	public void startup(Config config) throws Exception {
		String rconServer = config.get("BF3 Host");
		String rconPass = config.get("BF3 Password");

		HostAndPort host = HostAndPort.fromString(config.get("HTTP Host"));

		Server server = new Server();
		SelectChannelConnector connector = new SelectChannelConnector();
		connector.setPort(host.getPortOrDefault(8080));
		connector.setHost(host.getHostText());
		server.addConnector(connector);

		ResourceHandler resource_handler = new ResourceHandler();
		resource_handler.setDirectoriesListed(true);
		resource_handler.setWelcomeFiles(new String[] { "index.html" });
		String form = Thread.currentThread().getContextClassLoader()
				.getResource("frontend/").toExternalForm();
		resource_handler.setResourceBase(form);

		JSONContext.Server jsonContext = new JacksonJSONContextServer();
		Map<String, Object> options = newHashMap();
		options.put(ClientTransport.JSON_CONTEXT, jsonContext);

		bayeuxServer = new BayeuxServerImpl();
		bayeuxServer.addTransport(new WebSocketTransport(bayeuxServer));
		bayeuxServer.setOptions(options);
		bayeuxServer.start();

		ServletContextHandler context = new ServletContextHandler(
				ServletContextHandler.SESSIONS);
		context.setContextPath("/");
		context.addServlet(new ServletHolder(CometdServlet.class), "/cometd/*");
		context.getServletContext().setAttribute(BayeuxServer.ATTRIBUTE,
				bayeuxServer);
		HandlerList handlers = new HandlerList();
		handlers.setHandlers(new Handler[] { context, resource_handler,
				new DefaultHandler() });

		server.setHandler(handlers);

		server.start();

		ServerState state = new ServerState();
		RCONClient client = new RCONClient();

		serverSession = bayeuxServer.newLocalSession("InControl");
		serverSession.handshake();
		EventManager events = new EventManager(bayeuxServer, serverSession);
		StateUpdater updater = new StateUpdater(state, events);
		client.init(state, updater, events);
		IncontrolProtocol protocol = new IncontrolProtocol();
		protocol.init(client, state, bayeuxServer, serverSession);

		HostAndPort rcon = HostAndPort.fromString(rconServer);
		client.connect(rcon.getHostText(), rcon.getPort());
		client.login(rconPass);

		updater.init(client);

		// while(true) {
		// newLocalSession.getChannel("/hello").publish("o");
		// Uninterruptibles.sleepUninterruptibly(1000, TimeUnit.MILLISECONDS);
		// }
		// cometd.
		// server.join();
	}

	public BayeuxServerImpl getBayeuxServer() {
		return bayeuxServer;
	}

}
